home *** CD-ROM | disk | FTP | other *** search
- // ===========================================================
- // ctrlc.c - Ctrl-C, Ctrl-Break handlers. AT-BIOS int 15h hook
- // ===========================================================
- //
- // Modification History
- // ====================
- // -Sym- -Date- Who -Comments-
- // ===== ====== === ==========
- // none 093092 rp Modified to be standalone for upload to CI$.
- // Extracted some typedefs, etc. from header file(s).
- // Translated debug stuff, etc to more std syntax.
- //
- #include <dos.h>
-
- // ============================================================================
- // Note: All routines originally in file KBD.ASM, via TASM's ideal mode.
- // File translated to straight 'C' under Turbo C++ v1.0, as part of
- // eliminating all *.asm files from project. This file was then
- // updated to C++ and to conform w/ Borland C++ v3.10
- // ( different getvect() & setvect() typecasts, etc ). Net result,
- // all files in project now compile successfully in C++ mode.
- //
- // !! YOU WILL GET SYNTAX ERRORS IF YOU TRY TO COMPILE IN 'C' MODE !!
- // These are mainly due to the use of 'Boolean' instead of
- // 'enum Boolean'. There may be others.
- //
- // Note: This module assumes that all keyboard input is handled
- // (in another file) via BIOS int 16h functions. Thus the int 23h
- // intercept should never actually be seen. It HAS NOT been tested
- // with 'stdin' or 'cin' ! Note that int 23h may also called by abort
- // processing (e.g. via 'Abort, Retry, Ignore').
- //
- // Note: This file assumes routines are being run on an AT-class machine.
- // For an XT-class, the int 15h hook is NOT valid !
- //
- // Note: Repeated blowups have shown that variables declared inside of
- // interrupt handlers should be static ! This minimizes stack usage,
- // and prevents _chain_intr() from getting too confused.
- // ============================================================================
-
- ////////////////////////////////////
- // typedefs from header file <std.h>
- ////////////////////////////////////
- enum Boolean { False, True };
- typedef unsigned char uchar;
- typedef unsigned short ushort;
- typedef unsigned long ulong;
-
- //////////////////////////////
- // Global Functions, variables
- //////////////////////////////
- void init_keyboard(); // module initialization (hook int's)
- void term_keyboard(); // module termination (restore int's)
- Boolean breakflag = False; // set to True on Ctrl-Break, Ctrl-C
- Boolean sysRequest = False; // toggled on SysRq key.
- // used for debug enable/disable
-
- //////////////////
- // Local variables
- //////////////////
- static Boolean installed = False; // Installation flag
- static Boolean trap_dosbrk = True; // False will disable int 23h intercept
- static Boolean trap_biosbrk = True; // False will disable int 1Bh intercept
- static uchar old_dosbrk; // Saved dos break state. 'Break' will
- // be disabled if trap_dosbrk == True
- // and restored at program exit
-
- static void _interrupt (_far *old15h)(...) = 0; // saved interrupt vectors
- static void _interrupt (_far *old1Bh)(...) = 0;
- static void _interrupt (_far *old23h)(...) = 0;
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // The BIOS Ctrl-Break trap is easiest.
- // Just set the global breakflag & exit
- ///////////////////////////////////////////////////////////////////////////////
- static void _interrupt new1Bh(...)
- {
- breakflag = True;
- }
-
- /////////////////////////////////////////////////
- // The 80x86 family cpu's carry flag bit position
- /////////////////////////////////////////////////
- const unsigned CPU_CARRY = 0x0001;
-
- ///////////////////////////////////////////////////////////////////////////////
- // DOS Ctrl-C is a little more difficult.
- // First, set the global breakflag.
- // Then clear the cpu's carry flag to tell dos to ignore the 'error' of
- // a Ctrl-C character.
- //
- // Only argument we care about happens to be the farthest away on the stack !
- ///////////////////////////////////////////////////////////////////////////////
- #pragma argsused
- static void _interrupt _far new23h( unsigned bp, unsigned di, unsigned si,
- unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
- unsigned ax, unsigned ip, unsigned cs, unsigned flags, ... )
- {
- breakflag = True;
- flags &= ~CPU_CARRY;
- }
-
- //
- // trap keyboard scan codes on AT-class only
- //
- static Boolean trap_15h = True; // Needed if trap_sysreq or trap_scan
- static Boolean trap_sysreq = True; // Trap the SysRq key
- static Boolean trap_scan = False; // Trap any scan code other than sysreq
- static Boolean trap_prtsc = False; // Trap PrtSc key
- static Boolean trap_reboot = False; // Trap Ctrl-Alt-Del
-
- #define BIOS_DATA 0x40 // bios data segment
-
- const ushort SHIFT_FLAGS = 0x17; // shift key flags byte
- const uchar ALT_SHIFT = 0x08; // alt shift bit flag
- const uchar CTRL_SHIFT = 0x04; // ctrl shift bit flag
-
- const uchar CTRL_ALT = ALT_SHIFT | CTRL_SHIFT;
-
- #define FN_SYSREQ 0x85 // int 15h reg ah if sysreq hit, release
- #define FN_SCAN 0x4F // int 15h reg ah on key hit, release
-
- #define M_DEL 0x53 // delete key make
- #define M_PRTSC 0x37 // prtsc key make
-
- //
- // Maybe intercept the keyboard raw-scan codes, and SysReq keys.
- //
- #pragma argsused
- static void _interrupt _far new15h( unsigned bp, unsigned di, unsigned si,
- unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx,
- unsigned ax, unsigned ip, unsigned cs, unsigned flags, ...)
- {
- static uchar _far *shiftFlags =
- (uchar _far *)MK_FP( BIOS_DATA, SHIFT_FLAGS );
- static Boolean chain15h; // Should we chain to old handler ?
- static uchar regAH; // For clarity
- static uchar regAL;
-
- chain15h = True; // Set at each entry !
- regAL = (uchar) ax; // extract for clarity
- regAH = (uchar)(ax >> 8);
-
- ///////////////////
- // Maybe trap SysRq
- ///////////////////
- if ( regAH == FN_SYSREQ && trap_sysreq )
- {
- chain15h = False;
- if ( regAL )
- sysRequest = (sysRequest) ? False: True;
- }
- ////////////////////////
- // Maybe trap scan codes
- ////////////////////////
- else if ( regAH == FN_SCAN && trap_scan )
- {
- switch ( regAL )
- {
- case M_DEL:
- if ( trap_reboot && (*shiftFlags & CTRL_ALT) == CTRL_ALT )
- {
- flags &= ~CPU_CARRY; // discard scan code
- chain15h = False; // don't chain
- }
- break;
-
- case M_PRTSC:
- if ( trap_prtsc )
- {
- flags &= ~CPU_CARRY; // discard scan code
- chain15h = False; // don't chain
- }
- break;
-
- default:
- break; // all others pass thru
- }
- }
- if ( chain15h )
- _chain_intr( old15h );
- }
-
- /////////////////////////////////
- // term_keyboard() - unhook ints
- /////////////////////////////////
- void term_keyboard()
- {
- if ( !installed )
- return;
- if ( trap_15h )
- setvect( 0x15, old15h );
- if ( trap_biosbrk)
- setvect( 0x1B, old1Bh );
- if ( trap_dosbrk )
- {
- _AX = 0x3301; // set break state
- _DL = old_dosbrk; // to original
- geninterrupt( 0x21 );
- setvect( 0x23, old23h );
- }
- installed = False;
- }
-
- /////////////////////////////////////////
- // init_kybd() - keyboard initialization
- /////////////////////////////////////////
- void init_keyboard()
- {
- if ( installed )
- return;
- if ( trap_15h )
- {
- old15h = getvect( 0x15 );
- setvect( 0x15, (void _interrupt (_far*)(...)) new15h );
- }
- if ( trap_biosbrk )
- {
- old1Bh = getvect( 0x1B );
- setvect( 0x1B, new1Bh );
- }
- if ( trap_dosbrk )
- {
- _AX = 0x3302; // exchange break state
- _DL = 0; // to off
- geninterrupt( 0x21 );
- old_dosbrk = _DL; // save original
- old23h = getvect( 0x23 );
- setvect( 0x23, (void _interrupt (_far*)(...)) new23h );
- }
- installed = True;
- }
-